/*
 * Created on 2008-2-12
 *
 */
package jacky.lanlan.song.reflection.bean;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import jacky.lanlan.song.reflection.ReflectionUtils;
import jacky.lanlan.song.reflection.ReflectionUtils.MethodCallback;
import jacky.lanlan.song.reflection.ReflectionUtils.MethodFilter;
import jacky.lanlan.song.util.Assert;
import jacky.lanlan.song.lang.StringUtils;

/**
 * 操纵JavaBean的实用类，作为{@link jacky.lanlan.song.reflection.bean.BeanUtils}的补充，
 * 提供了它漏掉的处理Getter/Setter的功能。
 * @author Jacky.Song
 */
public abstract class JavaBeanUtils {

	enum MethodType{
		SETTER{
			@Override
			MethodFilter getFilter() {
				return MethodFilter.SETTER;
			}
			
			@Override
			boolean matchesPattern(Method method) {
				return isSetter(method);
			}
			
			@Override
			public String toString() {
				return "set";
			}
		},
		GETTER{
			@Override
			MethodFilter getFilter() {
				return MethodFilter.GETTER;
			}
			
			@Override
			boolean matchesPattern(Method method) {
				return isGetter(method);
			}
			
			@Override
			public String toString() {
				return "get";
			}
		},
		IS{
			@Override
			MethodFilter getFilter() {
				return GETTER.getFilter();
			}
			
			@Override
			boolean matchesPattern(Method method) {
				return GETTER.matchesPattern(method);
			}
			
			@Override
			public String toString() {
				return "is";
			}
		}
		;
		/**
		 * 对应该方法类型的过滤器。
		 */
		abstract MethodFilter getFilter();
		/**
		 * 判断给定方法是否符合JavaBean Setter/Getter规范。
		 * @param method 给定方法
		 * @return true如果是，false如果不是
		 */
		abstract boolean matchesPattern(Method method);
	}
	
	private static List<Method> extract(Class<?> bean,MethodType type) {
		final List<Method> list=new ArrayList<Method>(8);
		ReflectionUtils.doWithMethods(bean,
			new MethodCallback() {
  			public void doWith(Method method) throws IllegalArgumentException,
  					IllegalAccessException {
  				list.add(method);
  			}
  		},type.getFilter()
  	);
		return list;
	}
	
	/**
	 * 解析出所有Setter方法。
	 * @param bean JavaBean
	 * @return Setter方法列表
	 */
	public static List<Method> extractSetter(Class<?> bean) {
		return extract(bean,MethodType.SETTER);
	}
	
	/**
	 * 解析出所有Getter方法。
	 * @param bean JavaBean
	 * @return Getter方法列表
	 */
	public static List<Method> extractGetter(Class<?> bean) {
		return extract(bean,MethodType.GETTER);
	}
	
	/**
	 * 操作每个Setter方法。
	 * @param bean JavaBean
	 * @param getterHandler 执行操作的回调接口
	 */
	public static void doWithSetter(Class<?> bean,MethodCallback getterHandler) {
  	ReflectionUtils.doWithMethods(bean,getterHandler,MethodFilter.SETTER);
	}
	
	/**
	 * 操作每个Getter方法。
	 * @param bean JavaBean
	 * @param getterHandler 执行操作的回调接口
	 */
	public static void doWithGetter(Class<?> bean,MethodCallback getterHandler) {
  	ReflectionUtils.doWithMethods(bean,getterHandler,MethodFilter.GETTER);
	}
	
	private static String methodToPropName(Method method,MethodType type) {
		Assert.isTrue(type.matchesPattern(method),"方法 ["+method+"] 不是 "+type+" 方法");
		return StringUtils.uncapitalize(method.getName().substring(type.toString().length()));//去掉前缀后再decapitalize
	}
	
	/**
	 * Setter方法到属性名的转换。
	 * @param setter Setter方法
	 * @return Setter所对应的属性名
	 */
	public static String setterToPropName(Method setter) {
		return methodToPropName(setter,MethodType.SETTER);
	}
	
	/**
	 * Getter方法到属性名的转换。
	 * @param getter Getter方法
	 * @return Getter所对应的属性名
	 */
	public static String getterToPropName(Method getter) {
		MethodType type=getter.getName().startsWith("is") ? MethodType.IS : MethodType.GETTER;
		return methodToPropName(getter,type);
	}
	
	private static Method propNameToMethod(Class<?> bean,String propName,MethodType type) {
		StringBuilder methodName=new StringBuilder();
		methodName.append(type.toString().toLowerCase()). // 前缀小写
			append(StringUtils.capitalize(propName)) // 加上capitalize后的属性名
		;
		for(Method method:extract(bean, type)) {
			if(method.getName().equals(methodName.toString())) {
				return method;// 找到同名方法，返回
			}
		}
		return null;
	}
	
	/**
	 * 属性名到Getter方法的转换。
	 * @param bean JavaBean
	 * @param propName 属性名
	 * @return 该属性对应的Getter方法，如果没有则返回null
	 */
	public static Method propNameToGetter(Class<?> bean,String propName) {
		Method getter=propNameToMethod(bean,propName,MethodType.GETTER);
		if(getter == null) {
			getter=propNameToMethod(bean,propName,MethodType.IS);
		}
		return getter;
	}
	
	/**
	 * 属性名到Setter方法的转换。
	 * @param bean JavaBean
	 * @param propName 属性名
	 * @return 该属性对应的Setter方法，如果没有则返回null
	 */
	public static Method propNameToSetter(Class<?> bean,String propName) {
		return propNameToMethod(bean,propName,MethodType.SETTER);
	}
	
	/**
	 * 检测指定属性是否有对应Getter。
	 * @param bean JavaBean
	 * @param propName 指定属性名
	 * @return true如果有，false如果没有
	 */
	public static boolean hasGetter(Class<?> bean,String propName) {
		return propNameToGetter(bean,propName)!=null;
	}
	
	/**
	 * 检测指定属性是否有对应Setter。
	 * @param bean JavaBean
	 * @param propName 指定属性名
	 * @return true如果有，false如果没有
	 */
	public static boolean hasSetter(Class<?> bean,String propName) {
		return propNameToSetter(bean,propName)!=null;
	}
	
	/**
	 * 查看指定方法是否符合JavaBean的Setter规范(是否是一个Setter)。
	 * @param method 要检测的方法
	 * @return true如果是，false如果不是
	 */
	public static boolean isSetter(Method method) {
		return MethodFilter.SETTER.matches(method);
	}
	
	/**
	 * 查看指定方法是否符合JavaBean的Getter规范(是否是一个Getter)。
	 * @param method 要检测的方法
	 * @return true如果是，false如果不是
	 */
	public static boolean isGetter(Method method) {
		return MethodFilter.GETTER.matches(method);
	}

}
